#pragma once

#define UNICODE
#define NOMINMAX
#define _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>

#include <MSWSock.h>
#include <WS2tcpip.h>
#include <threadpoolapiset.h>

#include <algorithm>
#include <array>
#include <atomic>
#include <bitset>
#include <chrono>
#include <filesystem>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <thread>
#include <tuple>
#include <variant>
#include <vector>

#include "span.hpp"

namespace nonstd {
inline std::string to_string(const std::wstring& ws) {
    int len = ::WideCharToMultiByte(CP_ACP, 0, ws.data(), static_cast<int>(ws.size()), NULL, 0, NULL, NULL);
    std::string s(len + 1, 0);
    ::WideCharToMultiByte(CP_ACP, 0, ws.data(), static_cast<int>(ws.size()), s.data(), len, NULL, NULL);
    return s;
}

inline std::string to_string(const SOCKADDR_IN& addr) {
    char ip[25];
    return std::string(inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip))) + ":" + std::to_string(ntohs(addr.sin_port));
}

} // namespace nonstd

inline int64_t now_in_i64() {
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
    auto value = now_ms.time_since_epoch();
    return value.count();
}

inline std::chrono::time_point<std::chrono::system_clock> i64_to_time(int64_t duration) {
    std::chrono::milliseconds dur(duration);
    std::chrono::time_point<std::chrono::system_clock> dt(dur);
    return dt;
}

template <typename... Args>
struct overload : Args... {
    overload(Args&&... args)
        : Args(std::forward<Args>(args)...) {
    }
    using Args::operator()...;
};

template <typename... Args>
overload(Args...)->overload<Args...>;